#using <mscorlib.dll>
using namespace System;
using namespace System::Collections::Generic;
using namespace System::Drawing;
using namespace System::Runtime::InteropServices;

#include "helper.h"
#include "WebViewListenerWrapper.h"

ref class WebView;

namespace AwesomiumDotNet
{
	/// <summary>
	/// Mouse button enumerations,
	/// used with WebView.InjectMouseDown and WebView.InjectMouseUp
	/// </summary>
	public enum class MouseButton
	{
		Left, Right, Middle
	};
	
	/// <summary>
	/// Windows keyboard messages,
	/// used with WebView.InjectKeyboardEvent
	/// </summary>
	public enum class WM : Int32
	{
		KeyDown = WM_KEYDOWN,
		KeyUp = WM_KEYUP,
		Char = WM_CHAR,
		DeadChar = WM_DEADCHAR,
		SysKeyDown = WM_SYSKEYDOWN,
		SysKeyUp = WM_SYSKEYUP,
		SysChar = WM_SYSCHAR,
		SysDeadChar = WM_SYSDEADCHAR,
		UniChar = WM_UNICHAR,
		KeyFirst = WM_KEYFIRST,
		KeyLast = WM_KEYLAST,
	};

	delegate void BeginLoadingDelegate (const std::string& url, const std::wstring& frameName, int statusCode, const std::wstring& mimeType);
	delegate void BeginNavigationDelegate (const std::string& url, const std::wstring& frameName);
	delegate void CallbackDelegate (const std::string& name, const Awesomium::JSArguments& args);
	delegate void ChangeCursorDelegate (const HCURSOR& cursor);
	delegate void ChangeKeyboardFocusDelegate (bool isFocused);
	delegate void ChangeTargetUrlDelegate (const std::string& url);
	delegate void ChangeTooltipDelegate (const std::wstring& tooltip);
	delegate void FinishLoadingDelegate ();
	delegate void ReceiveTitleDelegate (const std::wstring& title, const std::wstring& frameName);

	/*
	Delegate wrapper structures for converting the
	managed delegates to unmanaged function pointers.
	*/
	value struct BeginLoadingWrapper {
		[MarshalAsAttribute(UnmanagedType::FunctionPtr)]
		BeginLoadingDelegate^ _Delegate; };
	value struct BeginNavigationWrapper {
		[MarshalAsAttribute(UnmanagedType::FunctionPtr)]
		BeginNavigationDelegate^ _Delegate; };
	value struct CallbackWrapper {
		[MarshalAsAttribute(UnmanagedType::FunctionPtr)]
		CallbackDelegate^ _Delegate; };
	value struct ChangeCursorWrapper {
		[MarshalAsAttribute(UnmanagedType::FunctionPtr)]
		ChangeCursorDelegate^ _Delegate; };
	value struct ChangeKeyboardFocusWrapper {
		[MarshalAsAttribute(UnmanagedType::FunctionPtr)]
		ChangeKeyboardFocusDelegate^ _Delegate; };
	value struct ChangeTargetUrlWrapper {
		[MarshalAsAttribute(UnmanagedType::FunctionPtr)]
		ChangeTargetUrlDelegate^ _Delegate; };
	value struct ChangeTooltipWrapper {
		[MarshalAsAttribute(UnmanagedType::FunctionPtr)]
		ChangeTooltipDelegate^ _Delegate; };
	value struct FinishLoadingWrapper {
		[MarshalAsAttribute(UnmanagedType::FunctionPtr)]
		FinishLoadingDelegate^ _Delegate; };
	value struct ReceiveTitleWrapper {
		[MarshalAsAttribute(UnmanagedType::FunctionPtr)]
		ReceiveTitleDelegate^ _Delegate; };

	/// <summary>
	/// A WebView is essentially a single instance of a web-browser
	/// (created via the WebCore singleton) that you can interact with
	/// (via input injection, javascript, etc.) and render to an off-screen buffer.
	/// </summary>
	public ref class WebView
	{

	private:
		Awesomium::WebView* webView;
		MyWebViewListener* myListener;

	public:
	event EventHandler<Args::BeginLoadingEventArgs^>^ OnBeginLoading;
	event EventHandler<Args::BeginNavigationEventArgs^>^ OnBeginNavigation;
	event EventHandler<Args::CallbackEventArgs^>^ OnCallback;
	event EventHandler<Args::ChangeCursorEventArgs^>^ OnChangeCursor;
	event EventHandler<Args::ChangeKeyboardFocusEventArgs^>^ OnChangeKeyboardFocus;
	event EventHandler<Args::ChangeTargetUrlEventArgs^>^ OnChangeTargetUrl;
	event EventHandler<Args::ChangeTooltipEventArgs^>^ OnChangeTooltip;
	event EventHandler<Args::FinishLoadingEventArgs^>^ OnFinishLoading;
	event EventHandler<Args::ReceiveTitleEventArgs^>^ OnReceiveTitle;

	private:
	BeginLoadingWrapper^ d_BeginLoading;
	BeginNavigationWrapper^ d_BeginNavigation;
	CallbackWrapper^ d_Callback;
	ChangeCursorWrapper^ d_ChangeCursor;
	ChangeKeyboardFocusWrapper^ d_ChangeKeyboardFocus;
	ChangeTargetUrlWrapper^ d_ChangeTargetURL;
	ChangeTooltipWrapper^ d_ChangeTooltip;
	FinishLoadingWrapper^ d_FinishLoading;
	ReceiveTitleWrapper^ d_ReceiveTitle;

	public:
		WebView (Awesomium::WebCore* webCore,
			int width, int height)
		{
			webView = webCore->createWebView(width, height);
			WebViewInit();
		}

	public:
		WebView (Awesomium::WebCore* webCore,
			int width, int height,
			bool isTransparent)
		{
			webView = webCore->createWebView(width, height, isTransparent);
			WebViewInit();
		}

	public:
		WebView (Awesomium::WebCore* webCore,
			int width, int height,
			bool isTransparent,
			bool enableAsyncRendering)
		{
			webView = webCore->createWebView(width, height, isTransparent, enableAsyncRendering);
			WebViewInit();
		}

	public:
		WebView (Awesomium::WebCore* webCore,
			int width, int height,
			bool isTransparent,
			bool enableAsyncRendering,
			int maxAsyncRenderPerSec)
		{
			webView = webCore->createWebView(width, height,
				isTransparent, enableAsyncRendering, maxAsyncRenderPerSec);
			WebViewInit();
		}

	public:
		virtual ~WebView()
		{
			if (webView != 0)
			{
				webView->setListener(0);
				webView->destroy();
				webView = 0;
			}
		}

	private:
		void WebViewInit ()
		{
			myListener = new MyWebViewListener();

			d_BeginNavigation = gcnew BeginNavigationWrapper();
			d_BeginLoading = gcnew BeginLoadingWrapper();
			d_FinishLoading = gcnew FinishLoadingWrapper();
			d_Callback = gcnew CallbackWrapper();
			d_ReceiveTitle = gcnew ReceiveTitleWrapper();
			d_ChangeTooltip = gcnew ChangeTooltipWrapper();
			d_ChangeCursor = gcnew ChangeCursorWrapper();
			d_ChangeKeyboardFocus = gcnew ChangeKeyboardFocusWrapper();
			d_ChangeTargetURL = gcnew ChangeTargetUrlWrapper();

			d_BeginNavigation->_Delegate =
				gcnew BeginNavigationDelegate(this, &WebView::onBeginNavigation);
			d_BeginLoading->_Delegate =
				gcnew BeginLoadingDelegate(this, &WebView::onBeginLoading);
			d_FinishLoading->_Delegate =
				gcnew FinishLoadingDelegate(this, &WebView::onFinishLoading);
			d_Callback->_Delegate =
				gcnew CallbackDelegate(this, &WebView::onCallback);
			d_ReceiveTitle->_Delegate =
				gcnew ReceiveTitleDelegate(this, &WebView::onReceiveTitle);
			d_ChangeTooltip->_Delegate =
				gcnew ChangeTooltipDelegate(this, &WebView::onChangeTooltip);
			d_ChangeCursor->_Delegate =
				gcnew ChangeCursorDelegate(this, &WebView::onChangeCursor);
			d_ChangeKeyboardFocus->_Delegate =
				gcnew ChangeKeyboardFocusDelegate(this, &WebView::onChangeKeyboardFocus);
			d_ChangeTargetURL->_Delegate =
				gcnew ChangeTargetUrlDelegate(this, &WebView::onChangeTargetUrl);

			BeginLoadingCallback cb_onBeginLoading;
			BeginNavigationCallback cb_onBeginNavigation;
			CallbackCallback cb_onCallback;
			ChangeCursorCallback cb_onChangeCursor;
			ChangeKeyboardFocusCallback cb_onChangeKeyboardFocus;
			ChangeTargetUrlCallback cb_onChangeTargetURL;
			ChangeTooltipCallback cb_onChangeTooltip;
			FinishLoadingCallback cb_onFinishLoading;
			ReceiveTitleCallback cb_onReceiveTitle;

			Marshal::StructureToPtr (d_BeginLoading, (IntPtr)&cb_onBeginLoading, false);
			Marshal::StructureToPtr (d_BeginNavigation, (IntPtr)&cb_onBeginNavigation, false);
			Marshal::StructureToPtr (d_Callback, (IntPtr)&cb_onCallback, false);
			Marshal::StructureToPtr (d_ChangeCursor, (IntPtr)&cb_onChangeCursor, false);
			Marshal::StructureToPtr (d_ChangeKeyboardFocus, (IntPtr)&cb_onChangeKeyboardFocus, false);
			Marshal::StructureToPtr (d_ChangeTargetURL, (IntPtr)&cb_onChangeTargetURL, false);
			Marshal::StructureToPtr (d_ChangeTooltip, (IntPtr)&cb_onChangeTooltip, false);
			Marshal::StructureToPtr (d_FinishLoading, (IntPtr)&cb_onFinishLoading, false);
			Marshal::StructureToPtr (d_ReceiveTitle, (IntPtr)&cb_onReceiveTitle, false);

			myListener->set_onBeginLoading(cb_onBeginLoading);
			myListener->set_onBeginNavigation(cb_onBeginNavigation);
			myListener->set_onCallback(cb_onCallback);
			myListener->set_onChangeCursor(cb_onChangeCursor);
			myListener->set_onChangeKeyboardFocus(cb_onChangeKeyboardFocus);
			myListener->set_onChangeTargetURL(cb_onChangeTargetURL);
			myListener->set_onChangeTooltip(cb_onChangeTooltip);
			myListener->set_onFinishLoading(cb_onFinishLoading);
			myListener->set_onReceiveTitle(cb_onReceiveTitle);

			webView->setListener(myListener);
		}

		void onBeginLoading (const std::string& url, const std::wstring& frameName, int statusCode, const std::wstring& mimeType)
		{
			Args::BeginLoadingEventArgs^ args = gcnew Args::BeginLoadingEventArgs(
				gcnew String(url.c_str()),
				gcnew String(frameName.c_str()),
				statusCode,
				gcnew String(mimeType.c_str()) );
			OnBeginLoading(this, args);
		}

		void onBeginNavigation (const std::string& url, const std::wstring& frameName)
		{
			Args::BeginNavigationEventArgs^ args = gcnew Args::BeginNavigationEventArgs(
				gcnew String(url.c_str()),
				gcnew String(frameName.c_str()) );
			OnBeginNavigation(this, args);
		}

		void onCallback (const std::string& name, const Awesomium::JSArguments& in_args)
		{
			List<JSValue^>^ out_args = gcnew List<JSValue^>();
			unsigned int i = 0;
			while(i < in_args.size())
			{
				const Awesomium::JSValue in_arg = in_args.at(i);
				if (in_args.at(i).isNull())
				{
					out_args->Add(gcnew JSValue());
				}
				else if (in_args.at(i).isBoolean())
				{
					out_args->Add(gcnew JSValue(in_arg.toBoolean()));
				}
				else if (in_args.at(i).isInteger())
				{
					out_args->Add(gcnew JSValue(in_arg.toInteger()));
				}
				else if (in_args.at(i).isDouble())
				{
					out_args->Add(gcnew JSValue(in_arg.toDouble()));
				}
				else if (in_args.at(i).isString())
				{
					String^ value = gcnew String(in_arg.toString().c_str());
					out_args->Add(gcnew JSValue(value));
				}
				i++;
			}
			Args::CallbackEventArgs^ cb_args = gcnew Args::CallbackEventArgs(
				gcnew String(name.c_str()),
				out_args
			);
			OnCallback(this, cb_args);
		}

		void onChangeCursor (const HCURSOR& cursor)
		{
			Args::ChangeCursorEventArgs^ args = gcnew Args::ChangeCursorEventArgs(
				//gcnew String(tooltip.c_str())
				);
			OnChangeCursor(this, args);
		}

		void onChangeKeyboardFocus (bool isFocused)
		{
			Args::ChangeKeyboardFocusEventArgs^ args = gcnew Args::ChangeKeyboardFocusEventArgs(
				isFocused );
			OnChangeKeyboardFocus(this, args);
		}

		void onChangeTargetUrl (const std::string& url)
		{
			Args::ChangeTargetUrlEventArgs^ args = gcnew Args::ChangeTargetUrlEventArgs(
				gcnew String(url.c_str())
				);
			OnChangeTargetUrl(this, args);
		}

		void onChangeTooltip (const std::wstring& tooltip)
		{
			Args::ChangeTooltipEventArgs^ args = gcnew Args::ChangeTooltipEventArgs(
				gcnew String(tooltip.c_str()) );
			OnChangeTooltip(this, args);
		}

		void onFinishLoading ()
		{
			OnFinishLoading(this, gcnew Args::FinishLoadingEventArgs());
		}

		void onReceiveTitle (const std::wstring& title, const std::wstring& frameName)
		{
			Args::ReceiveTitleEventArgs^ args = gcnew Args::ReceiveTitleEventArgs(
				gcnew String(title.c_str()),
				gcnew String(frameName.c_str()) );
			OnReceiveTitle(this, args);
		}


	// WebView functions

	public:
	  /// <summary>
	  /// Explicitly destroys this WebView instance. If you neglect to call this,
	  /// the WebCore singleton will automatically destroy all lingering WebView instances at shutdown.
	  /// </summary>
	  /// <remark>
	  /// This should NEVER be called directly from one of the notifications of WebViewListener.
	  /// </remark>
		void ::WebView::Destroy ()
		{
			delete this;
		}

	public:
	  /// <summary>
	  /// Notifies the current page that is has gained focus.
	  /// </summary>
		void ::WebView::Focus ()
		{
			webView->focus();
		}

	public:
	  /// <summary>
	  /// Notifies the current page that it has lost focus.
	  /// </summary>
		void ::WebView::Unfocus ()
		{
			webView->unfocus();
		}

	public:
	  /// <summary>
	  /// Invokes a 'copy' action using the system clipboard.
	  /// </summary>
		void ::WebView::Copy ()
		{
			webView->copy();
		}

	public:
	  /// <summary>
	  /// Invokes a 'cut' action using the system clipboard.
	  /// </summary>
		void ::WebView::Cut ()
		{
			webView->cut();
		}

	public:
	  /// <summary>
	  /// Invokes a 'paste' action using the system clipboard.
	  /// </summary>
		void ::WebView::Paste ()
		{
			webView->paste();
		}


	public:
	  /// <summary>
	  /// Selects all items on the current page.
	  /// </summary>
		void ::WebView::SelectAll ()
		{
			webView->selectAll();
		}

	public:
	  /// <summary>
	  /// Deselects all items on the current page.
	  /// </summary>
		void ::WebView::DeselectAll ()
		{
			webView->deselectAll();
		}

	public:
	  /// <summary>
	  /// Retrieves the content of the current page as plain text.
	  /// </summary>
	  /// <param name="maxChars">
	  /// The maximum number of characters to retrieve.
	  /// </param>
	  /// <returns>
	  /// Returns the retrieved text.
	  /// </returns>
	  /// <remark>
	  /// Warning: The performance of this function depends upon the number
	  /// of retrieved characters and the complexity of the page.
	  /// </remark>
		String^ GetContentAsText (int maxChars)
		{
			std::wstring resultstring;
			webView->getContentAsText(resultstring, maxChars);
			return gcnew String(resultstring.c_str());
		}

	public:
	  /// <summary>
	  /// Zooms into the page, enlarging by 20%.
	  /// </summary>
		void ZoomIn ()
		{
			webView->zoomIn();
		}

	public:
	  /// <summary>
	  /// Zooms out of the page, reducing by 20%.
	  /// </summary>
		void ZoomOut ()
		{
			webView->zoomOut();
		}

	public:
	  /// <summary>
	  /// Resets the zoom level.
	  /// </summary>
		void ResetZoom ()
		{
			webView->resetZoom();
		}

	public:
	  /// <summary>
	  /// Resizes this WebView to certain dimensions.
	  /// </summary>
	  /// <param name="width">
	  /// The width to resize to.
	  /// </param>
	  /// <param name="height">
	  /// The height to resize to.
	  /// </param>
		void Resize (int width, int height)
		{
			webView->resize(width, height);
		}

	public:
	  /// <summary>
	  /// Injects a mouse-move event in local coordinates.
	  /// </summary>
	  /// <param name="x">
	  /// The absolute x-coordinate of the mouse (localized to the WebView).
	  /// </param>
	  /// <param name="y">
	  /// The absolute y-coordinate of the mouse (localized to the WebView).
	  /// </param>
		void InjectMouseMove (int x, int y)
		{
			webView->injectMouseMove(x, y);
		}

	public:
	  /// <summary>
	  /// Injects a mouse-move event in local coordinates.
	  /// </summary>
	  /// <param name="position">
	  /// The absolute coordinates of the mouse (localized to the WebView).
	  /// </param>
		void InjectMouseMove (Point position)
		{
			webView->injectMouseMove(position.X, position.Y);
		}

	public:
	  /// <summary>
	  /// Injects a mouse-down event.
	  /// </summary>
	  /// <param name="button">
	  /// The button that was pressed.
	  /// </param>
		void InjectMouseDown (MouseButton button)
		{
			if (button == MouseButton::Left)
				webView->injectMouseDown(Awesomium::LEFT_MOUSE_BTN);
			else if (button == MouseButton::Right)
				webView->injectMouseDown(Awesomium::RIGHT_MOUSE_BTN);
			else if (button == MouseButton::Middle)
				webView->injectMouseDown(Awesomium::MIDDLE_MOUSE_BTN);
		}

	public:
	  /// <summary>
	  /// Injects a mouse-up event.
	  /// </summary>
	  /// <param name="button">
	  /// The button that was released.
	  /// </param>
		void InjectMouseUp (MouseButton button)
		{
			if (button == MouseButton::Left)
				webView->injectMouseUp(Awesomium::LEFT_MOUSE_BTN);
			else if (button == MouseButton::Right)
				webView->injectMouseUp(Awesomium::RIGHT_MOUSE_BTN);
			else if (button == MouseButton::Middle)
				webView->injectMouseUp(Awesomium::MIDDLE_MOUSE_BTN);
		}

	public:
	  /// <summary>
	  /// Injects a mouse-wheel event.
	  /// </summary>
	  /// <param name="scrollAmount">
	  /// The amount of pixels to scroll by.
	  /// </param>
		void InjectMouseWheel(int scrollAmount)
		{
			webView->injectMouseWheel(scrollAmount);
		}

	public:
	  /// <summary>
	  /// Injects a keyboard event.
	  /// </summary>
	  /// <remark>
	  /// The native Windows keyboard message should be passed,
	  /// msg can be one of the WM.* values.
	  /// </remark>
		void InjectKeyboardEvent (IntPtr hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
		{
			webView->injectKeyboardEvent((HWND)hwnd.ToPointer(), msg, wParam, lParam);
		}

	  /// <summary>
	  /// Injects a keyboard event.
	  /// </summary>
	  /// <remark>
	  /// The native Windows keyboard message should be passed.
	  /// </remark>
		void InjectKeyboardEvent (IntPtr hwnd, WM msg, WPARAM wParam, LPARAM lParam)
		{
			webView->injectKeyboardEvent((HWND)hwnd.ToPointer(), (UINT)msg, wParam, lParam);
		}

	public:
	  /// <summary>
	  /// Loads a URL into the WebView asynchronously.
	  /// </summary>
	  /// <param name="url">
	  /// The URL to load.
	  /// </param>
		void LoadUrl (String^ url)
		{
			Uri^ uri = gcnew Uri(url);
			LoadUrl(uri);
		}

	public:
	  /// <summary>
	  /// Loads a URL into the WebView asynchronously.
	  /// </summary>
	  /// <param name="url">
	  /// The URL to load.
	  /// </param>
		void LoadUrl (Uri^ url)
		{
			std::string urlstring;
			MarshalString(url->ToString(), urlstring);
			webView->loadURL(urlstring);
		}

	public:
	  /// <summary>
	  /// Loads a URL into the WebView asynchronously.
	  /// </summary>
	  /// <param name="url">
	  /// The URL to load.
	  /// </param>
	  /// <param name="frameName">
	  /// The name of the frame to load the URL in; leave this blank to load in the main frame.
	  /// </param>
		void LoadUrl (String^ url, String^ frameName)
		{
			Uri^ uri = gcnew Uri(url);
			LoadUrl(uri, frameName);
		}

	public:
	  /// <summary>
	  /// Loads a URL into the WebView asynchronously.
	  /// </summary>
	  /// <param name="url">
	  /// The URL to load.
	  /// </param>
	  /// <param name="frameName">
	  /// The name of the frame to load the URL in; leave this blank to load in the main frame.
	  /// </param>
		void LoadUrl (Uri^ url, String^ frameName)
		{
			std::string urlstring;
			std::wstring frameNamestring;
			MarshalString(url->ToString(), urlstring);
			MarshalString(frameName, frameNamestring);
			webView->loadURL(urlstring, frameNamestring);
		}

	public:
	  /// <summary>
	  /// Loads a URL into the WebView asynchronously.
	  /// </summary>
	  /// <param name="url">
	  /// The URL to load.
	  /// </param>
	  /// <param name="frameName">
	  /// The name of the frame to load the URL in; leave this blank to load in the main frame.
	  /// </param>
	  /// <param name="userName">
	  /// If the URL requires authentication, the username to authorize as.
	  /// </param>
	  /// <param name="password">
	  /// If the URL requires authentication, the password to use.
	  /// </param>
		void LoadUrl (String^ url, String^ frameName, String^ userName, String^ password)
		{
			std::string urlstring;
			std::wstring frameNamestring;
			std::string usernamestring, passwordstring;
			MarshalString(url, urlstring);
			MarshalString(frameName, frameNamestring);
			MarshalString(userName, usernamestring);
			MarshalString(password, passwordstring);
			webView->loadURL(urlstring, frameNamestring, usernamestring, passwordstring);
		}

	public:
	  /// <summary>
	  /// Loads a string of HTML into the WebView asynchronously.
	  /// </summary>
	  /// <param name="html">
	  /// The HTML string to load.
	  /// </param>
	  /// <remark>
	  /// The base directory (specified via WebCore.setBaseDirectory)
	  /// will be used to resolve relative URL's resources (such as images, links, etc).
	  /// </remark>
		void LoadHtml (String^ html)
		{
			std::string htmlstring;
			MarshalString(html, htmlstring);
			webView->loadHTML(htmlstring, L"");
		}

	public:
	  /// <summary>
	  /// Loads a string of HTML into the WebView asynchronously.
	  /// </summary>
	  /// <param name="html">
	  /// The HTML string to load.
	  /// </param>
	  /// <param name="frameName">
	  /// The name of the frame to load the HTML in; leave this blank to load in the main frame.
	  /// </param>
	  /// <remark>
	  /// The base directory (specified via WebCore.setBaseDirectory)
	  /// will be used to resolve relative URL's resources (such as images, links, etc).
	  /// </remark>
		void LoadHtml (String^ html, String^ frameName)
		{
			std::string htmlstring;
			std::wstring frameNamestring;
			MarshalString(html, htmlstring);
			MarshalString(frameName, frameNamestring);
			webView->loadHTML(htmlstring, frameNamestring);
		}

	public:
	  /// <summary>
	  /// Loads a local file into the WebView asynchronously.
	  /// </summary>
	  /// <param name="file">
	  /// The file to load.
	  /// </param>
	  /// <remark>
	  /// The file should exist within the base directory
	  /// (specified via WebCore.setBaseDirectory).
	  /// </remark>
		void LoadFile (String^ file)
		{
			std::string filestring;
			MarshalString(file, filestring);
			webView->loadFile(filestring);
		}

	public:
	  /// <summary>
	  /// Loads a local file into the WebView asynchronously.
	  /// </summary>
	  /// <param name="file">
	  /// The file to load.
	  /// </param>
	  /// <param name="frameName">
	  /// The name of the frame to load the file in; leave this blank to load in the main frame.
	  /// </param>
		void LoadFile (String^ file, String^ frameName)
		{
			std::string filestring;
			std::wstring frameNamestring;
			MarshalString(file, filestring);
			MarshalString(frameName, frameNamestring);
			webView->loadFile(filestring, frameNamestring);
		}

	public:
	  /// <summary>
	  /// Sets whether or not pages should be rendered with a transparent background-color.
	  /// </summary>
	  /// <param name="isTransparent">
	  /// Whether or not to force the background-color as transparent.
	  /// </param>
		void SetTransparent (bool isTransparent)
		{
			webView->setTransparent(isTransparent);
		}

	public:
	  /// <summary>
	  /// Renders the WebView to an off-screen buffer.
	  /// </summary>
	  /// <param name="destination">
	  /// The buffer to render to, its width and height should match the WebView's.
	  /// </param>
	  /// <param name="rowSpan">
	  /// The row-span of the destination buffer (number of bytes per row).
	  /// </param>
	  /// <param name="depth">
	  /// The depth (bytes per pixel) of the destination buffer. Valid options
	  /// include 3 (BGR/RGB) or 4 (BGRA/RGBA).
	  /// </param>
		void Render (array<System::Byte>^ destination, int rowSpan, int depth)
		{
			pin_ptr<unsigned char> bufPin = &destination[0];
			Render((int)bufPin, rowSpan, depth);
		}

	public:
	  /// <summary>
	  /// Renders the WebView to an off-screen buffer.
	  /// </summary>
	  /// <param name="destination">
	  /// The buffer to render to, its width and height should match the WebView's.
	  /// </param>
	  /// <param name="rowSpan">
	  /// The row-span of the destination buffer (number of bytes per row).
	  /// </param>
	  /// <param name="depth">
	  /// The depth (bytes per pixel) of the destination buffer. Valid options
	  /// include 3 (BGR/RGB) or 4 (BGRA/RGBA).
	  /// </param>
		void Render (int destination, int rowSpan, int depth)
		{
			webView->render((unsigned char*)destination, rowSpan, depth);
		}

	public:
	  /// <summary>
	  /// Renders the WebView to an off-screen buffer.
	  /// </summary>
	  /// <param name="destination">
	  /// The buffer to render to, its width and height should match the WebView's.
	  /// </param>
	  /// <param name="rowSpan">
	  /// The row-span of the destination buffer (number of bytes per row).
	  /// </param>
	  /// <param name="depth">
	  /// The depth (bytes per pixel) of the destination buffer. Valid options
	  /// include 3 (BGR/RGB) or 4 (BGRA/RGBA).
	  /// </param>
	  /// <param name="renderedRect">
	  /// If asynchronous rendering is not enabled,	you can provide
	  /// a pointer to a Rect to store the dimensions of the rendered area,
	  /// or rather, the dimensions of the area that actually changed
	  /// since the last render.
	  /// </param>
		void Render (array<System::Byte>^ destination, int rowSpan, int depth, System::Drawing::Rectangle renderedRect)
		{
			pin_ptr<unsigned char> bufPin = &destination[0];
			Render((int)bufPin, rowSpan, depth, renderedRect);
		}

	public:
	  /// <summary>
	  /// Renders the WebView to an off-screen buffer.
	  /// </summary>
	  /// <param name="destination">
	  /// The buffer to render to, its width and height should match the WebView's.
	  /// </param>
	  /// <param name="rowSpan">
	  /// The row-span of the destination buffer (number of bytes per row).
	  /// </param>
	  /// <param name="depth">
	  /// The depth (bytes per pixel) of the destination buffer. Valid options
	  /// include 3 (BGR/RGB) or 4 (BGRA/RGBA).
	  /// </param>
	  /// <param name="renderedRect">
	  /// If asynchronous rendering is not enabled,	you can provide
	  /// a pointer to a Rect to store the dimensions of the rendered area,
	  /// or rather, the dimensions of the area that actually changed
	  /// since the last render.
	  /// </param>
		void Render (int destination, int rowSpan, int depth, System::Drawing::Rectangle renderedRect)
		{
			Awesomium::Rect nativeRenderedRect;
			webView->render((unsigned char*)destination, rowSpan, depth, &nativeRenderedRect);
			renderedRect.X = nativeRenderedRect.x;
			renderedRect.Y = nativeRenderedRect.y;
			renderedRect.Width = nativeRenderedRect.width;
			renderedRect.Height = nativeRenderedRect.height;
		}

	public:
	  /// <summary>
	  /// Renders the WebView to an off-screen bitmap.
	  /// </summary>
	  /// <param name="width">
	  /// Width of the render.
	  /// </param>
	  /// <param name="height">
	  /// Height of the render.
	  /// </param>
		System::Drawing::Bitmap^ WebView::RenderToBitmap(int width, int height)
		{
			System::Drawing::Bitmap^ bmp = gcnew System::Drawing::Bitmap(
				width, height, System::Drawing::Imaging::PixelFormat::Format32bppArgb
			);

			System::Drawing::Imaging::BitmapData^ data = bmp->LockBits(
				System::Drawing::Rectangle(0,0, width, height),
				System::Drawing::Imaging::ImageLockMode::WriteOnly,
				System::Drawing::Imaging::PixelFormat::Format32bppArgb
			);

			webView->render((unsigned char*)(void*)data->Scan0, data->Stride, 4);
			bmp->UnlockBits(data);

			return bmp;
		}

	public:
	  /// <summary>
	  /// Returns whether or not the current web-view is dirty and needs to be re-rendered.
	  /// </summary>
	  /// <returns>
	  /// If the web-view is dirty, returns true, otherwise returns false.
	  /// </returns>
		bool IsDirty()
		{
			return webView->isDirty();
		}

	public:
	  /// <summary>
	  /// Navigates back/forward in history via a relative offset.
	  /// </summary>
	  /// <param name="offset">
	  /// The relative offset in history to navigate to.
	  /// </param>
	  /// <remarks>
	  /// For example, to go back one page:
	  ///   myView->goToHistoryOffset(-1);
	  /// Or, to go forward one page:
	  ///   myView->goToHistoryOffset(1);
	  /// </remarks>
		void GoToHistoryOffset(int offset)
		{
			webView->goToHistoryOffset(offset);
		}

	public:
	  /// <summary>
	  /// Executes a string of Javascript in the context of the current page asynchronously.
	  /// </summary>
	  /// <param name="javaScript">
	  /// The string of Javascript to execute.
	  /// </param>
		void ExecuteJavaScript (String^ javaScript)
		{
			std::string javascriptstring;
			MarshalString(javaScript, javascriptstring);
			webView->executeJavascript(javascriptstring);
		}

	public:
	  /// <summary>
	  /// Executes a string of Javascript in the context of the current page asynchronously.
	  /// </summary>
	  /// <param name="javaScript">
	  /// The string of Javascript to execute.
	  /// </param>
	  /// <param name="frameName">
	  /// The name of the frame to execute in; leave this blank to execute in the main frame.
	  /// </param>
		void ExecuteJavaScript (String^ javaScript, String^ frameName)
		{
			std::string javascriptstring;
			std::wstring frameNamestring;
			MarshalString(javaScript, javascriptstring);
			MarshalString(frameName, frameNamestring);
			webView->executeJavascript(javascriptstring, frameNamestring);
		}

	public:
	  /// <summary>
	  /// Sets a global 'Client' property that can be accessed via Javascript from
	  /// within all pages loaded into this web-view.
	  /// </summary>
	  /// <param name="name">
	  /// The name of the property.
	  /// </param>
	  /// <param name="value">
	  /// The javascript-value of the property.
	  /// </param>
	  /// <remarks>
	  /// You can access all properties you set via the 'Client' object using Javascript.
	  /// For example, if you set the property with a name of 'color' and a value of 'blue',
	  /// you could access this from the page using
	  /// Javascript: document.write("The color is " + Client.color);
	  /// </remarks>
		void SetProperty(String^ name, JSValue^ value)
		{
			std::string namestring;
			Awesomium::JSValue nativevalue;
			if (value->IsNull())
			{
				nativevalue = Awesomium::JSValue();
			}
			else if (value->IsBoolean())
			{
				nativevalue = Awesomium::JSValue(value->ToBoolean());
			}
			else if (value->IsInteger())
			{
				nativevalue = Awesomium::JSValue(value->ToInteger());
			}
			else if (value->IsDouble())
			{
				nativevalue = Awesomium::JSValue(value->ToDouble());
			}
			else if (value->IsString())
			{
				std::string stringvalue;
				MarshalString(value->ToString(), stringvalue);
				nativevalue = Awesomium::JSValue(stringvalue);
			}
			MarshalString(name, namestring);
			webView->setProperty(namestring, nativevalue);
		}

	public:
	  /// <summary>
	  /// Registers a global 'Client' callback that can be invoked via
	  /// Javascript from within all pages loaded into this view.
	  /// </summary>
	  /// <remarks>
	  /// The name of the callback. You can invoke the callback in Javascript as:
	  /// Client.your_name_here(arg1, arg2, ...);
	  /// </remarks>
		void SetCallback (String^ name)
		{
			std::string namestring;
			MarshalString(name, namestring);
			webView->setCallback(namestring);
		}
	};
}
